Objective
Explore some future scenarios based on past results in financial markets. This will help get a sense of some realistic future possibilites for fictional portfolio.
Step 1. Get Historical Returns
- S&P 500: monthly returns
(this work already done in ‘SP500.Rmd’)
## tip: set start date mth before you want data so that you will have mthly returns for full period
## (since there is no return calc for the first mth, by def)
sp500 <- getSymbols(Symbols="^GSPC", from="1969-12-01", auto.assign=FALSE)
head(sp500)## GSPC.Open GSPC.High GSPC.Low GSPC.Close GSPC.Volume GSPC.Adjusted
## 1969-12-01 0 94.47 92.78 93.22 9950000 93.22
## 1969-12-02 0 93.54 91.95 92.65 9940000 92.65
## 1969-12-03 0 93.05 91.25 91.65 11300000 91.65
## 1969-12-04 0 92.45 90.36 91.95 13230000 91.95
## 1969-12-05 0 92.91 91.14 91.73 11150000 91.73
## 1969-12-08 0 92.05 90.29 90.84 9990000 90.84
sp500_mth <- to.monthly(sp500)
sp500_mth_ret <- Return.calculate(sp500_mth$sp500.Close)
chart_Series(sp500_mth_ret)- Vanguard all-stocks: monthly returns
Step 2. Distribution of Returns
- Identify distribution of historical monthly returns
- Assuming approx normal distribution, identify:
- mean
- std dev
## drop first mth, which is NA (by def)
sp500_mth_ret <- sp500_mth_ret[-1,]
sp500_mth_ret_ave <- mean.geometric(sp500_mth_ret)
sp500_mth_ret_stdev <- StdDev(sp500_mth_ret) ## StdDev from PerformanceAnalytics
sp500_mth_min <- min(sp500_mth_ret, na.rm=TRUE)
sp500_mth_max <- max(sp500_mth_ret, na.rm=TRUE)
## annualized return over whole period
sp500_ttl_ann_ret <- Return.annualized(sp500_mth_ret, scale=12)Step 3. Monte Carlo Simulation
- Generate a monthly return for each month by random selection from the distribution identified above
- Calculate future value based on this selection of returns
- Repeat entire process multiple times to understand the expected range of possibilities
alternative:
- could look at rolling 5-yr, 7-yr, 10-yr performance (by month)
- use that distribution to create range of values for performance for those periods (rather than individual monthly returns)
amount <- 400000
nmth <- 60
nsims <- 40
returns_all <- data.frame()
for(s in 1:nsims){
returns <- data.frame(mth=NA, ret=NA)
for(r in 1:nmth){
returns[r,"mth"] <- r
returns[r,"ret"] <- rnorm(n=1, mean=sp500_mth_ret_ave[1], sd=sp500_mth_ret_stdev[1])
}
returns <- returns %>% mutate(yr=ceiling(mth/12)
)
returns <- returns %>% mutate(
sim=as.factor(s)
)
returns$amt <- NA
for(rr in 1:nrow(returns)){
returns[rr,'amt'] <- ifelse(rr==1,amount*(1+returns[rr,'ret']), returns[rr-1,'amt']*(1+returns[rr,'ret']))
}
returns_all <- bind_rows(returns_all, returns)
}Visualize balance over time
chart_title <- paste0('Monthly Returns for ',nsims,' simulations of ',nmth, ' months')
returns_all %>% ggplot(aes(x=mth, y=amt, color=sim))+geom_line()+
scale_y_continuous(labels=comma)+
theme(legend.position = 'none')+
labs(title=chart_title)## ave final amount
returns_amt <- returns_all %>% filter(mth==nmth) %>% select(mth, sim, amt)
chart_title <- paste0("Distribution of End Amt for ",nsims, " of ",nmth, " months")
plot_dist <- returns_amt %>% ggplot(aes(x=amt))+geom_histogram()+
scale_x_continuous(labels=comma)+
geom_vline(xintercept=mean(returns_amt$amt), color='blue')+
geom_vline(xintercept=median(returns_amt$amt), color='green')+
geom_vline(xintercept=quantile(returns_amt$amt, 0.25))+
geom_vline(xintercept=quantile(returns_amt$amt, 0.75))+
labs(title=chart_title)
ggplotly(plot_dist)median(returns_amt$amt)## [1] 552515.7
mean(returns_amt$amt)## [1] 561901.3
quantile(returns_amt$amt, 0.25)## 25%
## 433268.6
quantile(returns_amt$amt, 0.75)## 75%
## 646698.5